﻿// ***********************************************************************
// Provided for Informational Purposes Only
//
// Apache 2.0 License
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY 
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR 
// PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
//
// See the Apache Version 2.0 License for specific language governing
// permissions and limitations under the License.
// ***********************************************************************
// Assembly  : ContractMeow.WinRT
// File      : QueryStringSerializer.cs
//
// ***********************************************************************
using ContractMeow.WinRT.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace ContractMeow.WinRT.Serialization
{
	public class QueryStringSerializer : IQueryStringSerializer
	{
		public QueryStringSerializer() { }

		public async Task<String> SerializeAsync(Object obj)
		{
			if (obj == null)
				return String.Empty;

			string objString = obj as string;
			if (objString != null)
			{
				if (objString.Split('=').Length % 2 == 0)
					return objString.UrlEncode();
				return String.Format("{0}=", (obj as String).UrlEncode());
			}

			return await Task.Run(
				() =>
				{
					IEnumerable<String> parameters = obj is IDictionary<String, String>
						? (obj as IDictionary<String, String>)
							.Select(kvp => String.Format("{0}={1}", kvp.Key.UrlEncode(), kvp.Value.UrlEncode()))
						: obj
							.GetType()
							.GetTypeInfo()
							.DeclaredProperties
							.Where(prop => prop.GetValue(obj) != null)
							.Select(prop =>
									String.Format("{0}={1}",
													prop.Name.UrlEncode(),
													GetStringValue(prop.GetValue(obj))));

					return String.Join("&", parameters);
				});
		}

		private String GetStringValue(Object obj)
		{
			return obj is Boolean
					   ? obj.ToString().ToLower()
					   : obj.Coalesce().UrlEncode();
		}
	}
}